﻿using System.Collections;
using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

public class MacroArgumentList : SourceNode, IReadOnlyList<MacroArgument>
{
    private SyntaxList<MacroArgument>? _arguments;

    private SourceNode? _leftParenthesisToken;
    private SourceNode? _rightParenthesisToken;

    internal MacroArgumentList(SourceNode? parent) :
        base(parent, SyntaxKinds.MacroArgumentList)
    {
    }

    public override int Start =>
        _leftParenthesisToken?.Start ?? _arguments?.Start ?? 0;


    public override int End =>
        _rightParenthesisToken?.End ?? _arguments?.End ?? 0;


    public override int Width
    {
        get
        {
            int len = _arguments?.Width ?? 0;
            if (_rightParenthesisToken == null)
            {
                return len;
            }

            int rightLen = _rightParenthesisToken.End - Start;
            len = rightLen > 0 ? rightLen : len;
            return len;
        }
    }


    public SourceNode? LeftParenthesisToken => _leftParenthesisToken;

    public SourceNode? RightParenthesisToken => _rightParenthesisToken;

    public MacroArgument this[int index] =>
        _arguments == null
            ? throw new IndexOutOfRangeException(nameof(index))
            : _arguments[index];

    public int Count => _arguments?.Count ?? 0;


    public IEnumerator<MacroArgument> GetEnumerator()
    {
        return _arguments == null
            ? Enumerable.Empty<MacroArgument>().GetEnumerator()
            : _arguments.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public void Add(MacroArgument argument)
    {
        _arguments ??= [];
        _arguments.Add(argument);
    }

    public void AddRange(IEnumerable<MacroArgument?>? arguments)
    {
        if (arguments == null)
        {
            return;
        }

        foreach (MacroArgument? arg in arguments)
        {
            if (arg != null)
            {
                Add(arg);
            }
        }
    }


    public MacroArgumentList Update(SourceNode? leftParen, SourceNode? rightParen)
    {
        Debug.Assert(leftParen == null || leftParen.IsNode(SyntaxKinds.LeftParenthesisToken));
        Debug.Assert(rightParen == null || rightParen.IsNode(SyntaxKinds.RightParenthesisToken));
        SetChildNullableField(ref _leftParenthesisToken, leftParen);
        SetChildNullableField(ref _rightParenthesisToken, rightParen);
        return this;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        AcceptList(visitor, _arguments);
    }
}


public static partial class NodeFactory
{
    public static MacroArgumentList CreateMacroArgumentList(SourceNode? parent, SourceNode? leftParenthesis,
        SourceNode? rightParenthesis, IEnumerable<MacroArgument>? arguments)
    {
        MacroArgumentList list = new(parent);
        list.AddRange(arguments);
        return list.Update(leftParenthesis, rightParenthesis);
    }
}